package erfgame.core.xml;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.URL;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.transform.Source;
import javax.xml.transform.Templates;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
import org.apache.batik.util.XMLResourceDescriptor;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.svg.SVGDocument;
import org.xml.sax.SAXException;

public class XmlUtil {
    
    private static final Logger log = Logger.getLogger(XmlUtil.class.getName());
    
    public static final String getResourceAsString( String resourceName ) {
        URL url = XmlUtil.class.getResource(resourceName);
        return url.toExternalForm();
    }
    
    public static final Source getResourceAsSource( String resourceName, DocumentBuilder documentBuilder ) throws IOException, SAXException {
        URL url = XmlUtil.class.getResource(resourceName);
        if( url == null ) {
            throw new RuntimeException( "no such resource "+resourceName );
        }
        InputStream ins = url.openStream();
        try {
            Document document = documentBuilder.parse(ins);
            if( log.isLoggable( Level.INFO ) ) {
                log.info("XSL: "+toString(document) );
            }
            return new DOMSource(document, url.toExternalForm());
        } finally {
            ins.close();
        }
    }
    
    public static final Templates newTemplates( final Source source, final TransformerFactory transformerFactory ) {
        return new Templates() {

            public Properties getOutputProperties() {
                try {
                    return transformerFactory.newTransformer(source).getOutputProperties();
                } catch( Exception ex ) {
                    throw new RuntimeException( "error reading properties", ex );
                }
            }

            public Transformer newTransformer()
                    throws TransformerConfigurationException {
                return transformerFactory.newTransformer(source);
            }
            
        };
    }
    
    public static final String toString( Node document ) {
        StringWriter sw = new StringWriter();
        StreamResult result = new StreamResult( sw );
        DOMSource source = new DOMSource( document );
        try {
            Transformer transformer = TransformerFactory.newInstance().newTransformer();
            transformer.transform(source, result);
            return sw.toString();
        } catch( Exception ex ) {
            throw new RuntimeException( "unable to toString document", ex );
        }
    }
    
    public static final String transformToSVGString( DocumentBuilder documentBuilder, ObjectXMLFactory xmlFactory, Object o, Transformer transformer ) 
        throws TransformerException, IOException{
		Document document = documentBuilder.newDocument();
		document.setXmlStandalone(true);
		Node node = xmlFactory.toXML(o, document);
		document.appendChild(node);
        //DOMSource xmlSource = new DOMSource(node);
		// TODO should be able to use the DOM directly, think this is something to do with namespaces, whatever it is, it's retarded
		String documentString = XmlUtil.toString(document);
		Source xmlSource = new StreamSource( new StringReader( documentString ) );
		
		// magic to make it use an SVG element
//		DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
//		String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
//		Document svg = impl.createDocument(svgNS, "svg", null);
		
		//DOMResult outputTarget =  new DOMResult();
		StringWriter sw = new StringWriter();
		StreamResult outputTarget = new StreamResult(sw);
		transformer.transform(xmlSource, outputTarget);
		if( log.isLoggable(Level.INFO) ) {
            log.info("XML: "+XmlUtil.toString(node) );
		    log.info("SVG: "+sw.toString() );
		}    	
		return sw.toString();
    }
    
    public static final SVGDocument stringToSVG( String s ) 
    	throws IOException {
        String parser = XMLResourceDescriptor.getXMLParserClassName();
        SAXSVGDocumentFactory f = new SAXSVGDocumentFactory(parser);
        return f.createSVGDocument(null, new StringReader(s));   	
    }
    
    public static final SVGDocument transformToSVG( DocumentBuilder documentBuilder, ObjectXMLFactory xmlFactory, Object o, Transformer transformer ) 
    	throws TransformerException, IOException {
		String s = transformToSVGString(documentBuilder, xmlFactory, o, transformer);
	    // TODO : using the generated DOM directly doesn't really work either (although it should), using streams instead
		return stringToSVG(s);
    }
}
